package com.wsx.ones.monitor.core.loader;

import com.wsx.ones.monitor.common.util.FinalStaticUtil;
import com.wsx.ones.monitor.core.common.ChannelState;
import com.wsx.ones.monitor.core.executer.RpcThreadFactory;
import com.wsx.ones.monitor.core.netty.PullChannelHandler;
import com.wsx.ones.monitor.core.serialize.ProtocolSelecter;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

import java.util.concurrent.ConcurrentHashMap;

/**
 * 服务端启动的抽象类设计
 * 该基类是提供给其他类继承用的，用过用到spring容器，可以设置到容器启动后的加载
 * 如果是简单的jar实现，可以继承该类，实现main方法，调用start方法启动该类
 *
 * public class ServerTest {
 *      public static void main(String[] args) {
 *          RpcServerStarterTest starter = new RpcServerStarterTest("hession:127.0.0.1:6770");
 *          starter.startServer();
 *      }
 *  }
 *
 *  class RpcServerStarterTest extends RpcServerStarter {
 *      public RpcServerStarterTest(String addr) {
 *          super(addr);
 *      }
 *      @Override
 *      public ConcurrentHashMap<String, Object> getRpcBeanMap() {
 *          ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<String, Object>();
 *          map.put("com.wsx.ones.monitor.core.sample.TestInterface", new TestInterfaceImpl());
 *          return map;
 *      }
 * }
 *
 * Created by wangshuaixin on 17/2/7.
 */
public abstract class RpcServerStarter extends RpcServerBase {

    private String inetAddress;

    private String[] addrs;

    //链接的服务端通道
    private ChannelFuture future = null;

    //根据设置的url来实现不同的序列化和服务器暴露端口
    public RpcServerStarter(String inetAddress) {
        this.inetAddress = inetAddress;
        setRpcSerializeProtocol(inetAddress);
    }

    private void setRpcSerializeProtocol(String inetAddress) {
        this.addrs = inetAddress.split(FinalStaticUtil.DELIMITER);
        setRpcSerializeProtocol(ProtocolSelecter.getProtocol(addrs[0]));
    }


    /**
     * netty的server端启动的核心实现
     * 下面是netty的服务端的标准实现
     *
     */
    public synchronized void startServer() {
        //

        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup work = new NioEventLoopGroup(PROCESS, new RpcThreadFactory(FinalStaticUtil.RPC_NETTY_FACTORY));

        try {
            //netty的实现
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(boss, work)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childOption(ChannelOption.TCP_NODELAY, true)
                    .childHandler(new PullChannelHandler(rpcSerializeProtocol, getRpcBeanMap()));

            //服务状态为初始化
            state = ChannelState.INIT;

            //地址的参数控制
            if (addrs.length == 3) {
                String host = addrs[1];
                int port = Integer.valueOf(addrs[2]);
                //绑定服务器
                future = bootstrap.bind(host, port).sync();

                //服务状态未启动
                state = ChannelState.ALIVE;

                future.channel().closeFuture().sync();
            }

        } catch (InterruptedException e) {
            state = ChannelState.UNALIVE;
            e.printStackTrace();
        } finally {
            work.shutdownGracefully();
            boss.shutdownGracefully();

            state = ChannelState.CLOSED;
        }
    }

    /**
     * 该类是供子类来实现的，获得rpc服务调用的实际实现类
     * key是该类对应实现接口的全路径
     * value是该实现类的初始化的bean
     * @return
     */
    public abstract ConcurrentHashMap<String, Object> getRpcBeanMap();
}
